<template>
  <div class="app-container">
    <el-form
      v-show="showSearch"
      ref="queryFormRef"
      :inline="true"
      :model="queryParams"
    >
      <el-form-item
        :label="$t('system.menu.menuName')"
        prop="menuName"
      >
        <el-input
          v-model="queryParams.menuName"
          clearable
          :placeholder="$t('system.menu.enterMenuName')"
          @keyup.enter="handleQuery"
        />
      </el-form-item>
      <el-form-item
        :label="$t('system.menu.status')"
        prop="status"
      >
        <el-select
          v-model="queryParams.status"
          clearable
          :placeholder="$t('system.menu.menuStatus')"
        >
          <el-option
            v-for="dict in statusOptions"
            :key="dict.dictValue"
            :label="dict.dictLabel"
            :value="dict.dictValue"
          />
        </el-select>
      </el-form-item>
      <el-form-item
        :label="$t('system.menu.position')"
        prop="status"
      >
        <el-radio-group v-model="queryParams.location">
          <el-radio-button :value="''">
            {{ $t("system.menu.all") }}
          </el-radio-button>
          <el-radio-button value="2">
            {{ $t("system.menu.frontendMenu") }}
          </el-radio-button>
          <el-radio-button value="1">
            {{ $t("system.menu.backendMenu") }}
          </el-radio-button>
        </el-radio-group>
      </el-form-item>
      <el-form-item>
        <el-button
          icon="ele-Search"
          type="primary"
          @click="handleQuery"
        >
          {{ $t("formI18n.all.search") }}
        </el-button>
        <el-button
          icon="ele-Refresh"
          @click="resetQuery"
        >
          {{ $t("formI18n.all.reset") }}
        </el-button>
      </el-form-item>
    </el-form>

    <el-row
      :gutter="10"
      class="mb8"
    >
      <el-col :span="1.5">
        <el-button
          v-hasPermi="['system:menu:add']"
          icon="ele-Plus"
          plain
          type="primary"
          @click="handleAdd"
        >
          {{ $t("system.menu.handleAdd") }}
        </el-button>
      </el-col>
      <right-toolbar
        v-model:show-search="showSearch"
        @query-table="getList"
      />
    </el-row>

    <el-table
      v-loading="loading"
      :data="menuList"
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
      row-key="id"
    >
      <el-table-column
        :show-overflow-tooltip="true"
        :label="$t('system.menu.menuName')"
        prop="menuName"
        width="160"
      />
      <el-table-column
        align="center"
        :label="$t('system.menu.icon')"
        prop="icon"
        width="100"
      >
        <template #default="scope">
          <i :class="scope.row.icon" />
        </template>
      </el-table-column>
      <el-table-column
        :label="$t('system.menu.sortOrder')"
        prop="orderNum"
        width="100"
      />
      <el-table-column
        :show-overflow-tooltip="true"
        :label="$t('system.menu.permission')"
        prop="perms"
      />
      <el-table-column
        :show-overflow-tooltip="true"
        :label="$t('system.menu.component')"
        prop="component"
      />
      <el-table-column
        :formatter="statusFormat"
        :label="$t('system.menu.status')"
        prop="status"
        width="80"
      />
      <el-table-column
        align="center"
        :label="$t('system.menu.position')"
        prop="createTime"
      >
        <template #default="scope">
          <span v-if="scope.row.menuType === 'M' || scope.row.parentId === 0">
            <el-tag v-if="scope.row.location === '2'">{{ $t("system.menu.frontendMenu") }}</el-tag>
            <el-tag
              v-else
              type="info"
            >
              {{ $t("system.menu.backendMenu") }}
            </el-tag>
          </span>
          <span v-else></span>
        </template>
      </el-table-column>
      <el-table-column
        align="center"
        :label="$t('system.menu.createTime')"
        prop="createTime"
      >
        <template #default="scope">
          <span>{{ parseTime(scope.row.createTime) }}</span>
        </template>
      </el-table-column>
      <el-table-column
        align="center"
        :label="$t('system.menu.updateTime')"
        prop="updateTime"
      >
        <template #default="scope">
          <span>{{ parseTime(scope.row.updateTime) }}</span>
        </template>
      </el-table-column>
      <el-table-column
        align="center"
        class-name="small-padding fixed-width"
        :label="$t('formI18n.all.operate')"
      >
        <template #default="scope">
          <el-button
            link
            type="primary"
            icon="ele-Edit"
            @click="handleUpdate(scope.row)"
            v-hasPermi="['system:menu:edit']"
          ></el-button>
          <el-button
            link
            type="primary"
            icon="ele-Plus"
            @click="handleAdd(scope.row)"
            v-hasPermi="['system:menu:add']"
          ></el-button>
          <el-button
            link
            type="primary"
            icon="ele-Delete"
            @click="handleDelete(scope.row)"
            v-hasPermi="['system:menu:remove']"
          ></el-button>
        </template>
      </el-table-column>
    </el-table>

    <!-- 添加或修改菜单对话框 -->
    <el-dialog
      :title="title"
      v-model="open"
      append-to-body
      width="40%"
      :close-on-click-modal="false"
    >
      <el-form
        ref="formRef"
        :model="form"
        :rules="rules"
        label-width="110px"
      >
        <el-row>
          <el-col :span="24">
            <el-form-item :label="$t('system.menu.parentMenu')">
              <el-tree-select
                v-model="form.parentId"
                :data="menuOptions"
                @change="handleTreeSelect"
                :props="{ value: 'id', label: 'menuName', children: 'children' }"
                value-key="id"
                :placeholder="$t('system.menu.selectParentMenu')"
                check-strictly
              />
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item
              :label="$t('system.menu.menuType')"
              prop="menuType"
            >
              <el-radio-group v-model="form.menuType">
                <el-radio
                  value="M"
                  v-if="!['M', 'C', 'F'].includes(parentType)"
                >
                  {{ $t("system.menu.catalog") }}
                </el-radio>
                <el-radio
                  value="C"
                  v-if="!['C', 'F'].includes(parentType)"
                >
                  {{ $t("system.menu.menu") }}
                </el-radio>
                <el-radio
                  value="F"
                  v-if="!['M', 'F'].includes(parentType)"
                >
                  {{ $t("system.menu.button") }}
                </el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item :label="$t('system.menu.menuIcon')">
              <el-popover
                placement="bottom-start"
                trigger="click"
                width="460"
                @show="$refs['iconSelect'].reset()"
              >
                <IconSelect
                  ref="iconSelect"
                  @selected="selected"
                />
                <template #reference>
                  <el-input
                    v-model="form.icon"
                    :placeholder="$t('system.menu.clickSelectIcon')"
                    readonly
                  >
                    <template #prefix>
                      <i
                        v-if="form.icon"
                        :class="form.icon"
                        style="height: 32px; width: 16px"
                      />
                    </template>
                  </el-input>
                </template>
              </el-popover>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item
              :label="$t('system.menu.menuName')"
              prop="menuName"
            >
              <el-input
                v-model="form.menuName"
                :placeholder="$t('system.menu.enterMenuName')"
              />
            </el-form-item>
          </el-col>
          <el-col
            :span="12"
            v-if="form.menuType != 'F'"
          >
            <el-form-item
              :label="$t('system.menu.langKey')"
              prop="langKey"
            >
              <el-input
                v-model="form.langKey"
                :placeholder="$t('system.menu.enterLangKey')"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item
              :label="$t('system.menu.sortOrder')"
              prop="orderNum"
            >
              <el-input-number
                v-model="form.orderNum"
                :min="0"
                controls-position="right"
              />
            </el-form-item>
          </el-col>
          <el-col
            :span="12"
            v-if="form.menuType == 'C'"
          >
            <el-form-item :label="$t('system.menu.externalLink')">
              <el-radio-group v-model="form.isFrame">
                <el-radio value="0">{{ $t("system.menu.yes") }}</el-radio>
                <el-radio value="1">{{ $t("system.menu.no") }}</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col
            :span="12"
            v-if="form.menuType !== 'F'"
          >
            <el-form-item
              :label="$t('system.menu.routePath')"
              prop="path"
            >
              <el-input
                v-model="form.path"
                :placeholder="$t('system.menu.enterRouteAddress')"
              />
            </el-form-item>
          </el-col>
          <el-col
            :span="12"
            v-if="form.menuType == 'C'"
          >
            <el-form-item
              label-width="150px"
              :label="$t('system.menu.component')"
              prop="component"
            >
              <el-input
                v-model="form.component"
                :placeholder="$t('system.menu.enterComponent')"
              />
            </el-form-item>
          </el-col>
          <el-col
            :span="12"
            v-if="form.menuType != 'M'"
          >
            <el-form-item
              label-width="130px"
              :label="$t('system.menu.permission')"
            >
              <el-input
                v-model="form.perms"
                maxlength="100"
                :placeholder="$t('system.menu.enterPermissionIdentifier')"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item
              :label="$t('system.menu.visible')"
              v-if="form.menuType != 'F'"
            >
              <el-radio-group v-model="form.visible">
                <el-radio
                  v-for="dict in visibleOptions"
                  :key="dict.dictValue"
                  :value="dict.dictValue"
                >
                  {{ dict.dictLabel }}
                </el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item
              :label="$t('system.menu.menuStatus')"
              v-if="form.menuType != 'F'"
            >
              <el-radio-group v-model="form.status">
                <el-radio
                  v-for="dict in statusOptions"
                  :key="dict.dictValue"
                  :value="dict.dictValue"
                >
                  {{ dict.dictLabel }}
                </el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <!--          <el-col-->
          <!--            :span="12"-->
          <!--            v-if="form.menuType == 'C'"-->
          <!--          >-->
          <!--            <el-form-item :label="$t('system.menu.cache')">-->
          <!--              <el-radio-group v-model="form.isCache">-->
          <!--                <el-radio value="0">{{ $t("system.menu.cache") }}</el-radio>-->
          <!--                <el-radio value="1">{{ $t("system.menu.noCache") }}</el-radio>-->
          <!--              </el-radio-group>-->
          <!--            </el-form-item>-->
          <!--          </el-col>-->
          <el-col :span="12">
            <el-form-item
              :label="$t('system.menu.menuPosition')"
              v-if="form.menuType == 'M'"
            >
              <el-radio-group v-model="form.location">
                <el-radio value="1">{{ $t("system.menu.backendMenu") }}</el-radio>
                <el-radio value="2">{{ $t("system.menu.frontendMenu") }}</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button
            type="primary"
            @click="submitForm"
          >
            {{ $t("formI18n.all.confirm") }}
          </el-button>
          <el-button @click="cancel">{{ $t("formI18n.all.cancel") }}</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup lang="ts">
import { nextTick, onMounted, ref } from "vue";
import { addMenu, delMenu, getMenu, listMenu, MenuEntity, updateMenu } from "@/api/system/menu";
import IconSelect from "./IconfontSelect.vue";
import { i18n } from "@/i18n";
import type { FormInstance } from "element-plus";
import { ElMessageBox } from "element-plus";
import { getDicts } from "@/api/system/dict/data";
import { handleTree, parseTime, resetFormRef, selectDictLabel } from "@/utils/tduck";
import { MessageUtil } from "@/utils/messageUtil";

// 状态和引用
const loading = ref(true);
const showSearch = ref(true);
const menuList = ref<MenuEntity[]>([]);
const menuOptions = ref<any[]>([]);
const title = ref("");
const open = ref(false);
const visibleOptions = ref<any[]>([]);
const statusOptions = ref<any[]>([]);
const queryParams = ref({
  menuName: undefined,
  visible: undefined,
  location: undefined,
  status: undefined
});
const form = ref<any>({
  id: undefined,
  parentId: 0,
  menuName: undefined,
  icon: undefined,
  menuType: "M",
  orderNum: undefined,
  isFrame: "1",
  isCache: "0",
  visible: "0",
  status: "0",
  location: "1",
  langKey: ""
});
const parentType = ref("");

const formRef = ref<FormInstance | null>(null);
const queryFormRef = ref<FormInstance | null>(null);

// 表单校验规则
const rules = {
  menuName: [{ required: true, message: i18n.global.t("system.menu.menuNameRequied"), trigger: "blur" }],
  orderNum: [{ required: true, message: i18n.global.t("system.menu.menuOrderRequied"), trigger: "blur" }],
  path: [{ required: true, message: i18n.global.t("system.menu.routeRequied"), trigger: "blur" }]
};

// 生命周期钩子
onMounted(() => {
  getList();
  getDicts("sys_show_hide").then((response: any) => {
    visibleOptions.value = response.data;
  });
  getDicts("sys_normal_disable").then((response: any) => {
    statusOptions.value = response.data;
  });
});

// 方法定义
const selected = (name: string) => {
  form.value.icon = name;
};

const getList = () => {
  loading.value = true;
  listMenu(queryParams.value).then(response => {
    const list = !queryParams.value.location
      ? response.data
      : filterMenuByTypeAndLocation(response.data, queryParams.value.location);
    menuList.value = handleTree(list, "id");
    loading.value = false;
  });
};

function filterMenuByTypeAndLocation(menuArray: MenuEntity[], location: string | undefined): MenuEntity[] {
  // 递归函数，查找某个父菜单的所有子菜单
  function findChildren(parentId: number | undefined, menuArray: MenuEntity[], result: MenuEntity[]) {
    const children = menuArray.filter(menu => menu.parentId == parentId);
    result.push(...children);
    for (const child of children) {
      findChildren(child.id, menuArray, result); // 递归查找子菜单
    }
    return children;
  }

  // 过滤出符合条件的顶级菜单项 兼容没有设置的默认菜单
  const topLevelMenus = menuArray.filter(
    menu => menu.menuType === "M" && (menu.location == location || (queryParams.value.location == "1" && !menu.location))
  );

  // 为每个顶级菜单项查找其所有的子集
  const result: MenuEntity[] = [];
  for (const menu of topLevelMenus) {
    result.push(menu);
    findChildren(menu.id, menuArray, result);
  }

  return result;
}

const getTreeSelect = () => {
  listMenu({}).then(response => {
    menuOptions.value = [];
    const menu = { id: 0, menuName: i18n.global.t("system.menu.topMenu"), children: [] };
    menu.children = handleTree(response.data, "id") as [];
    menuOptions.value.push(menu);
  });
};

const handleTreeSelect = (id: number) => {
  getMenu(id).then(res => {
    if (res.data) {
      parentType.value = res.data.menuType;
    } else {
      parentType.value = "";
    }
    form.value.menuType = "";
  });
};

const statusFormat = (row: any) => {
  if (row.menuType == "F") {
    return "";
  }
  return selectDictLabel(statusOptions.value, row.status);
};

const cancel = () => {
  open.value = false;
  reset();
};

const reset = () => {
  form.value = {
    id: undefined,
    parentId: 0,
    menuName: undefined,
    icon: undefined,
    menuType: "M",
    orderNum: undefined,
    isFrame: "1",
    isCache: "0",
    visible: "0",
    status: "0",
    location: "1",
    langKey: ""
  };
  resetFormRef(formRef);
};

const handleQuery = () => {
  getList();
};

const resetQuery = () => {
  resetFormRef(queryFormRef);
  handleQuery();
};

const handleAdd = (row?: any) => {
  parentType.value = "";
  getTreeSelect();
  open.value = true;
  nextTick(() => {
    reset();
    if (row && row.id) {
      form.value.parentId = row.id;
    } else {
      form.value.parentId = 0;
    }
  });
  title.value = i18n.global.t("system.menu.addMenu");
};

const handleUpdate = (row: any) => {
  getTreeSelect();
  getMenu(row.id).then(response => {
    open.value = true;
    nextTick(() => {
      reset();
      form.value = response.data;
    });
    title.value = i18n.global.t("system.menu.modifyMenu");
  });
};

const submitForm = () => {
  formRef.value!.validate((valid: boolean) => {
    if (valid) {
      if (form.value.id !== undefined) {
        updateMenu(form.value).then(() => {
          MessageUtil.success(i18n.global.t("formI18n.all.success"));
          open.value = false;
          getList();
        });
      } else {
        addMenu(form.value).then(() => {
          MessageUtil.success(i18n.global.t("formI18n.all.success"));
          open.value = false;
          getList();
        });
      }
    }
  });
};

const handleDelete = (row: any) => {
  ElMessageBox.confirm(i18n.global.t("system.menu.isDelete"), i18n.global.t("formI18n.all.waring"), {
    confirmButtonText: i18n.global.t("formI18n.all.confirm"),
    cancelButtonText: i18n.global.t("formI18n.all.cancel"),
    type: "warning"
  })
    .then(() => {
      return delMenu(row.id);
    })
    .then(() => {
      getList();
      MessageUtil.success(i18n.global.t("formI18n.all.success"));
    })
    .catch(() => {});
};
</script>
